<?php

/* 
 * 微信支付
 * @author wyb
 */
namespace Api\Extend\Payment;
class Weixin {
    
    private $_url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
    private $_appid = ''; //应用ID
    private $_appsecret = '';
    private $_mch_id = ''; //支付商户号
    private $_data = array(); //数据集合
    private $_notify_url = 'http://w3.newbeemall.com/zt_forward/notify.php?payment=weixin';
    private $_appcliect_cart = null;
    private $_appcliect_key = null;

    public function __construct( $conf ) {
		$this->_appid = $conf['app_id'];
		$this->_appsecret = $conf['pay_aign_kay'];
		$this->_mch_id = $conf['partner_id'];
        $this->_customs = $conf['port'];
        $this->_data = array(
            'appid' => $this->_appid,
            'mch_id' => $this->_mch_id,
            'nonce_str' => $this->_nonceStr(), //随机字符串
        );
        $this->_appcliect_cart = SITE_FILE . $conf['cert'];
        $this->_appcliect_key = SITE_FILE . $conf['key'];
    }
    
	/**
     * PC生成支付字符串
     * @param type $order_info
     */
	public function pay( $order_info ) {
		
	}
	
    /**
     * 手机端生成支付字符串
     * @param type $order_info
     */
    public function pay_mobile( $order_info ) {

        $this->_data['trade_type'] = 'JSAPI';
        
        $extends = M('order')->where(array('ref' => $order_info['ref']))->find();
        $order_data = array(
            'body'  => $order_info['pay_body'],
            'out_trade_no'  => $order_info['ref'] . '_' . $extends['ref_extend'],
            'total_fee' => (int)($order_info['amount_total'] * 100),
            'spbill_create_ip'  => $this->_get_client_ip(),
            'notify_url' => $order_info['notify_url'] ? $order_info['notify_url'] : $this->_notify_url,
			'openid' =>$order_info['openid']
        );
        $this->_data = array_merge( $this->_data , $order_data );
        $this->_sign();
        $result = $this->_getData();
        $getData = (array)simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA);
        if( !$getData || $getData['return_code'] == 'FAIL' || ($getData['return_code'] == 'SUCCESS' && $getData['result_code'] == 'FAIL') ) {
            return array( 'msg' => '支付异常，请联系客服！' , 'status' => false );
        } else {
            $new_sign = array(
                'appId' => $this->_appid,
                'timeStamp' => time(),
                'nonceStr'  => $this->_nonceStr(),
                'package'  => 'prepay_id=' . $getData['prepay_id'],
				'signType' => 'MD5'
            );
            $this->_data = $new_sign;
            $this->_sign();
header("Content-type:text/html;charset=utf-8");
echo <<<Eof
<html>
<head>
    <meta http-equiv="content-type" content="text/html;charset=utf-8"/>
    <title>微信安全支付</title>
    <script type="text/javascript">
    	function onBridgeReady(){
    	   WeixinJSBridge.invoke(
    		   'getBrandWCPayRequest', {
    			   "appId":"{$new_sign['appId']}",     //公众号名称，由商户传入     
    			   "timeStamp":"{$new_sign['timeStamp']}",         //时间戳，自1970年以来的秒数     
    			   "nonceStr":"{$new_sign['nonceStr']}", //随机串     
    			   "package":"{$new_sign['package']}",     
    			   "signType":"MD5",         //微信签名方式：     
    			   "paySign":"{$this->_data['sign']}" //微信签名 
    		   },
    		   function(res){     
    			   if(res.err_msg == "get_brand_wcpay_request:ok" ) {
                        document.location="{$order_info['return_url']}";
                   } else {
                        alert('支付失败');
                   }     // 使用以上方式判断前端返回,微信团队郑重提示：res.err_msg将在用户支付成功后返回    ok，但并不保证它绝对可靠。 
    		   }
    	   ); 
    	}
        function callpay()
        {
        	if (typeof WeixinJSBridge == "undefined"){
        	   if( document.addEventListener ){
        		   document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
        	   }else if (document.attachEvent){
        		   document.attachEvent('WeixinJSBridgeReady', onBridgeReady); 
        		   document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
        	   }
        	}else{
        	   onBridgeReady();
        	}
        }
        document.addEventListener('WeixinJSBridgeReady', function onBridgeReady() {
           callpay();
        })
    </script>
</head>
<body></body>
</html>
Eof;
        }
    }
    
    /**
     * function：订单支付完成后回写数据库(微信支付回调)
     * @return json
     */
    public function notify( $getData ){
        //判断支付成功
        if( $getData['return_code'] == "SUCCESS" && $getData['result_code'] == 'SUCCESS' && $getData['appid'] == $this->_appid && $getData['mch_id'] == $this->_mch_id) {
            //签名验证
            $this->_data = $getData;
            unset( $this->_data['sign'] );
            $this->_sign();
            if( $this->_data['sign'] == $getData['sign'] ) {
                if( !$getData['out_trade_no'] ) return array('status' => 'error');
				$this->_data = array(
                    'return_code' => '<![CDATA[SUCCESS]]>',
                    'return_msg'  => '<![CDATA[OK]]>'
                );

                $out_trade_no = explode('_' , $getData['out_trade_no']);

                echo $this->_xmlData();
                return array('total_fee' => $getData['total_fee'] / 100 , 'payment_no' => $getData['transaction_id'] , 'order_sn' => $out_trade_no[0] , 'status' => 'success' );
            }
        }
        //支付失败修改订单
        
        $this->_data = array(
            'return_code' => '<![CDATA[FAIL]]>',
            'return_msg'  => '<![CDATA[error]]>'
        );
        echo $this->_xmlData();
        return array('status' => 'error');
    }

    /**
     * 订单退款
     */
    public function orderRefund( $order_data , $price) {
        $this->_url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
        //退款数据
        $refund_data = array(
            'out_trade_no' => $order_data['ref'] . '_' . $order_data['ref_extend'],
            'out_refund_no' => $order_data['ref'] . '_' . $order_data['ref_extend'],
            'total_fee' => $order_data['amount_total'] * 100,
            'refund_fee' => $price * 100,
            'op_user_id' => $this->_mch_id,
            'refund_account' => 'REFUND_SOURCE_RECHARGE_FUNDS'
        );

        $this->_data = array_merge( $this->_data , $refund_data );
        $this->_sign();
        $result = $this->_getData( 1 );
        $getData = (array)simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA);
        if( !$result || !$getData || $getData['return_code'] == 'FAIL' ) {
            return array( 'msg' => '支付异常，请联系客服！' , 'status' => false );
        } else if(  $getData['result_code'] == 'FAIL' ) {
            return array( 'msg' => "code：". $getData['err_code'] . " 错误描述：".$getData['err_code_des'] , 'status' => false );
        } else {
            return array( 'msg' => '退款成功' , 'status' => true );
        }
    }

    /**
     * 退款查询
     */
    public function refundQuery( $order_data ) {
        $this->_url = 'https://api.mch.weixin.qq.com/pay/refundquery';
        //查询数据
        $query_data = array(
            'out_trade_no' => $order_data['ref'] . '_' . $order_data['ref_extend']
        );

        $this->_data = array_merge( $this->_data , $query_data );
        $this->_sign();
        $result = $this->_getData();
        $getData = (array)simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA);
        if( $getData['return_code'] == 'SUCCESS' ) {
            //退款成功
            if( $getData['result_code'] == 'SUCCESS' ) {
                $state = 7;
            } else { //退款失败
                $state = 6;
                $msg = $getData['err_code_des'];
            }
            //信息修改
            M('order')->save(array('state' => $state , 'id' => $order_data['id'] , 'refund_query_error' => $msg ));
            $order_data['state'] = $state;
            $order_data['refund_query_error'] = $msg;
            //推送给第三方用户
            D('Common/OrderPaySend')->refundSendInfo( $order_data );
        } else {
            //退款异常
            M('order')->save(array('state' => 5 , 'id' => $order_data['id']));
        }
    }


    /**
     * 微信清关
     */
    public function clearance( $data ) {
        $this->_url = 'https://api.mch.weixin.qq.com/cgi-bin/mch/customs/customdeclareorder';
        $this->_data = array(
            'appid' => $this->_appid,
            'mch_id' => $this->_mch_id,
            'customs' => $this->_customs
        );
        
        $data['out_trade_no'] .= '_' . $data['ref_extend'];
        $this->_data['transaction_id'] = $data['transaction_id'];
        $this->_data['out_trade_no'] = $data['out_trade_no'];
        $this->_sign();
        $result = $this->_getData();
        $result = (array)simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA);
        $return_data = array();
        if( $result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS' ) {
            $return_data = array(
                'state' => 2 , 'msg' => '' , 'status' => true
            );
        } else if( $result['result_code'] == 'FAIL') { 
            $return_data = array(
                'state' => 1 , 'msg' => $result['err_code_des'] , 'status' => false
            );
        } else if( $result['return_code'] == 'FAIL' ) {
            $return_data = array(
                'state' => 1 , 'msg' => $result['return_msg'] , 'status' => false
            );
        }
        return $return_data;
    }

    /**
     * 清关查询
     */
    public function clearanceSelect( $data ) {
        $this->_url = 'https://api.mch.weixin.qq.com/cgi-bin/mch/customs/customdeclarequery';
        $this->_data = array(
            'appid' => $this->_appid,
            'mch_id' => $this->_mch_id,
            'sign_type' => 'MD5',
            'customs' => $this->_customs
        );
        
        $this->_data['transaction_id'] = $data['transaction_id'];
        $this->_sign();
        $result = $this->_getData();
        $result = (array)simplexml_load_string($result, 'SimpleXMLElement', LIBXML_NOCDATA);
        $return_data = array();
        if( $result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS' ) {
            if( $result['state_0'] == 'SUCCESS') {
                $return_data = array( 'state' => 4 , 'msg' => '' );
            } else if( $result['state_0'] == 'FAIL' ) {
                $return_data = array( 'state' => 3 , 'msg' => $result['explanation_0'] );
            } else if( $result['state_0'] == 'EXCEPT') {
                $return_data = array( 'state' => 3 , 'msg' => '海关接口异常' );
            }
        }
        return $return_data;
    }

    /**
     * 生成xml
     * @return string
     */
    private function _xmlData() {
        $xml_data = "<xml>";
        foreach( $this->_data as $key => $value ) {
            $xml_data .= "<$key>$value</$key>";
        }
        $xml_data .= "</xml>";
        return $xml_data;
    }
    
    /**
     * 签名价签
     */
    private function _sign() {
        ksort( $this->_data );
        reset( $this->_data );
        $sign_data = array();
        foreach( $this->_data as $key => $value ) {
            if( $value != '' ) {
                $sign_data[] = "$key=$value";
            }
        }
        $sign_data = implode('&' , $sign_data ) . "&key=".$this->_appsecret;
        $this->_data['sign'] = strtoupper( md5( $sign_data ) );
    }
    
    /**
    * 获取客户端IP地址
    * @param integer $type 返回类型 0 返回IP地址 1 返回IPV4地址数字
    * @param boolean $adv 是否进行高级模式获取（有可能被伪装） 
    * @return mixed
    */
    private function _get_client_ip($type = 0,$adv=false) {
       $type       =  $type ? 1 : 0;
       static $ip  =   NULL;
       if ($ip !== NULL) return $ip[$type];
       if($adv){
           if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
               $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
               $pos    =   array_search('unknown',$arr);
               if(false !== $pos) unset($arr[$pos]);
               $ip     =   trim($arr[0]);
           }elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
               $ip     =   $_SERVER['HTTP_CLIENT_IP'];
           }elseif (isset($_SERVER['REMOTE_ADDR'])) {
               $ip     =   $_SERVER['REMOTE_ADDR'];
           }
       }elseif (isset($_SERVER['REMOTE_ADDR'])) {
           $ip     =   $_SERVER['REMOTE_ADDR'];
       }
       // IP地址合法验证
       $long = sprintf("%u",ip2long($ip));
       $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);
       return $ip[$type];
   }
   
   /**
    * 随机字符串
    */
   private function _nonceStr(){
       $str = 'ABCDEF1234567890GHIJKLMNOPQRSTUVWXYZ1234567890';
       $str_data = '';
       $strlen = strlen( $str );
       for( $i=1; $i<=32; $i++ ) {
           $str_data .= $str[rand(0,$strlen-1)];
       }
       return $str_data;
   }
   
   /**
     * 发送请求
     */
    private function _getData( $is_refound = 0) {
	    $data = $this->_xmlData( $this->_data );
        $ci = curl_init();
        curl_setopt( $ci, CURLOPT_URL, $this->_url);
        curl_setopt($ci,CURLOPT_TIMEOUT, 30 );
        curl_setopt($ci,CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ci,CURLOPT_SSL_VERIFYPEER,false);
        curl_setopt($ci,CURLOPT_SSL_VERIFYHOST,false);
        if( $is_refound == 1 ) {
            curl_setopt($ci,CURLOPT_SSLCERT, $this->_appcliect_cart);
            curl_setopt($ci,CURLOPT_SSLKEY, $this->_appcliect_key);
        }
        curl_setopt( $ci, CURLOPT_HTTPHEADER, array( "Content-type: text/xml" ));
        curl_setopt( $ci, CURLOPT_POST, 1);
        curl_setopt( $ci, CURLOPT_POSTFIELDS,  $data );
        if( curl_errno( $ci ) ){
            print curl_error($ci);
        }
        $result = curl_exec( $ci );
        $status = curl_getinfo( $ci );
        curl_close($ci);
        return $result;
    }
}

